<template>
    <vxe-column v-bind="$attrs" tree-node>
      <template #header="scope">
        <div class="tree-node-tips">
          <VxeCheckbox
            v-if="$attrs.type == 'checkbox'"
            class="tree-node-tips-title"
            :indeterminate="(scope as any).indeterminate"
            :model-value="(scope as any).checked"
            :disabled="(scope as any).disabled"
            @change="
              () =>
                toggleAllCheckboxEvent(
                  (scope as any).indeterminate,
                  (scope as any).checked
                )
            "
          >
            {{ $attrs.title }}
          </VxeCheckbox>
          <span v-else class="tree-node-tips-title">
            {{ $attrs.title }}
          </span>
          <template v-if="!isEmpty && maxLevel > 1">
            <b
              v-for="level in maxLevel"
              :key="level"
              class="tree-node-tips-option"
              :class="{ actived: activedLevel === level }"
              @click="changeActivedLevel(level)"
              >{{ level }}
            </b>
          </template>
        </div>
      </template>
  
      <template v-if="hasRowSolt" #default="{ row }">
        <slot :row="row"></slot>
      </template>
    </vxe-column>
  </template>
  
  <script setup lang="ts">
    import { type VxeTableProps } from 'vxe-table';
    import {
      type PropType,
      onMounted,
      nextTick,
      ref,
      inject,
      computed,
      useSlots
    } from 'vue';
    import { PAGEINATION_INSTANCE } from './index';
  
    const props = defineProps({
      rowField: {
        type: String as PropType<string>,
        required: true
      }
    });
  
    const maxLevel = ref(1);
  
    const activedLevel = ref(1);
  
    const {
      getTableInstance,
      on: tageEvent,
      setLoading
    } = inject<PagenationTableInstance>(PAGEINATION_INSTANCE)!;
  
    const changeActivedLevel = async (level: number, isRefresh = false) => {
      try {
        if (activedLevel.value == level && !isRefresh) return Promise.reject();
        activedLevel.value = level;
        const $table = getTableInstance()!;
        setLoading(true);
        let openedKeys: string[] = [];
        let i = level;
        while (i > 1) {
          i--;
          const keys = levelMap.value.get(i) || [];
          openedKeys = openedKeys.concat(keys);
        }
        const rows = openedKeys.map((id) => $table.getRowById(id));
        requestIdleCallback(() => {
          $table.setAllTreeExpand(false);
          $table.setTreeExpand(rows, true);
          setLoading(false);
        });
        return Promise.resolve();
      } catch (error) {
        return Promise.reject(error);
      }
    };
  
    const countLevel = (data: any, level = 1, hashMap: Map<number, string[]>) => {
      maxLevel.value = Math.max(maxLevel.value, level);
      if (hashMap.get(level) != undefined) {
        hashMap.get(level)!.push(data[props.rowField]);
      } else {
        hashMap.set(level, [data[props.rowField]]);
      }
      if (data.children) {
        data.children.forEach((child: any) =>
          countLevel(child, level + 1, hashMap)
        );
      }
    };
  
    const levelMap = ref<Map<number, string[]>>(new Map());
  
    const isEmpty = ref(false);
  
    const initLevel = async (props: VxeTableProps) => {
      try {
        const $table = getTableInstance();
        const { fullData } = $table!.getTableData();
        isEmpty.value = fullData.length == 0;
        const hashMap: Map<number, string[]> = new Map();
        maxLevel.value = 1;
        fullData.forEach((row: any) => countLevel(row, 1, hashMap));
        levelMap.value = hashMap;
        await nextTick();
        if (props.treeConfig?.expandAll) {
          changeActivedLevel(maxLevel.value, true);
        } else {
          changeActivedLevel(activedLevel.value, true);
        }
        return Promise.resolve();
      } catch (error) {
        console.log(error);
      }
    };
  
    const toggleAllCheckboxEvent = (indeterminate: boolean, checked: boolean) => {
      const $table = getTableInstance();
      const rows = $table?.getTableData().visibleData;
      if (indeterminate) {
        $table!.setCheckboxRow(rows, true);
      } else {
        $table!.setCheckboxRow(rows, !checked);
      }
    };
  
    const solts = useSlots();
  
    const hasRowSolt = computed(() => {
      return !!solts['default'];
    });
  
    onMounted(() => {
      tageEvent('refresh', initLevel);
      tageEvent('sortChange', initLevel);
    });
  </script>
  
  <style lang="less">
    .tree-node-tips {
      display: flex;
      flex-direction: row;
      align-items: center;
      white-space: nowrap;
      flex-wrap: wrap;
      &-title {
        margin-right: 12px;
      }
  
      &-option {
        display: inline-block;
        text-align: center;
        width: 24px;
        height: 24px;
        line-height: 24px;
        margin-right: 8px;
        border-radius: 24px;
        background-color: transparent;
        cursor: pointer;
        font-weight: normal;
        &.actived {
          background-color: var(--el-color-primary);
          color: #fff;
        }
      }
    }
  </style>
  